package com.koron.common.web.electronicsignature.controller;

import com.alibaba.fastjson.JSONObject;
import com.github.tobato.fastdfs.service.DefaultFastFileStorageClient;
import com.koron.bean.base.Attachment;
import com.koron.bean.base.Response;
import com.koron.common.core.business.common.service.AttachmentService;
import com.koron.common.core.business.configsettings.utils.ConfigInfoTool;
import com.koron.common.core.config.ThreadLocalContext;
import com.koron.common.core.util.StringUtils;
import com.koron.common.core.util.dfs.FastDFSClientWrapper;
import com.koron.common.web.electronicsignature.bean.ElectronicSignature;
import com.koron.common.web.electronicsignature.bean.ElectronicSignatureQuery;
import com.koron.common.web.electronicsignature.service.ElectronicSignatureService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.koron.ebs.mybatis.ADOConnection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;
import org.springframework.util.DigestUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLDecoder;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@RestController
@RequestMapping("/ElectronicSignature")
@Api(tags = "电子签章")
public class ElectronicSignatureController {

    @Autowired
    private FastDFSClientWrapper fdfsCient;

    @Autowired
    private DefaultFastFileStorageClient storageClient;

    private String getCurrDs() {
        return ThreadLocalContext.get().getCurrDs();
    }

    private static Map<String, String> map = ConfigInfoTool.getConfigByCode("common", "electronic_signature");

    private static String baseUrl = map.get("baseUrl");
    private static String appToken = map.get("appToken");
    private static String appSecret = map.get("appSecret");
    private static String tenantName = map.get("tenantName");
    private static String categoryId = map.get("categoryId");

    private static final long timestamp = new Date().getTime() / 1000;
    private static final String signString = appToken + appSecret + timestamp;
    private static final String signature = DigestUtils.md5DigestAsHex(signString.getBytes());

    private static final Map<String, String> headerParams;

    static {
        headerParams = new HashMap();
        headerParams.put("x-qys-accesstoken", appToken);
        headerParams.put("x-qys-timestamp", String.valueOf(timestamp));
        headerParams.put("x-qys-signature", signature);
    }

    @Autowired
    private ElectronicSignatureService electronicSignatureService;

    @Autowired
    private AttachmentService attachmentService;

    @PostMapping("/createByFile")
    @ApiOperation(value = "创建文档")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "fileType", value = "文件类型(doc, docx, txt, pdf, png, gif, jpg, jpeg, tiff, html, rtf, xls, txt)", required = true, dataType = "String"),
            @ApiImplicitParam(name = "title", value = "文件名称", required = true, dataType = "String"),
            @ApiImplicitParam(name = "workTicketId", value = "业务id", required = true, dataType = "String")})
    public Response createByFile(@RequestParam(value = "file", required = false) MultipartFile file,
                                 @RequestParam(value = "fileId", required = false) String fileId,
                                 @RequestParam(value = "fileType") String fileType,
                                 @RequestParam(value = "title") String title,
                                 @RequestParam("workTicketId") String workTicketId) {
        String url = baseUrl + "/document/createbyfile";
        Map<String, String> formData = new HashMap<>();
        formData.put("fileType", fileType);
        formData.put("title", title);
        return ADOConnection.runTask(getCurrDs(), electronicSignatureService, "createByFile", Response.class, url, file, formData, headerParams, workTicketId, fileId);
    }

    @GetMapping("/createByCategory")
    @ApiOperation(value = "创建合同")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "subject", value = "合同名称", required = true, dataType = "String"),
            @ApiImplicitParam(name = "documentId", value = "文档id", required = true, dataType = "String"),
            @ApiImplicitParam(name = "createName", value = "合同创建人姓名", required = true, dataType = "String"),
            @ApiImplicitParam(name = "creatorContact", value = "合同创建人手机号码", required = true, dataType = "String"),
            @ApiImplicitParam(name = "tenantNameForSign", value = "签约主体名称", required = true, dataType = "String"),
            @ApiImplicitParam(name = "contact", value = "接收人联系方式", required = true, dataType = "String"),
            @ApiImplicitParam(name = "workTicketId", value = "业务id", required = true, dataType = "String"),
            @ApiImplicitParam(name = "sn", value = "合同编号，对接方系统中的业务编号", required = true, dataType = "String")
    })
    public Response createByCategory(@RequestParam("subject") String subject,
                                     @RequestParam("documentId") String documentId,
                                     @RequestParam("createName") String createName,
                                     @RequestParam("creatorContact") String creatorContact,
                                     @RequestParam("tenantNameForSign") String tenantNameForSign,
                                     @RequestParam("contact") String contact,
                                     @RequestParam("workTicketId") String workTicketId,
                                     @RequestParam("sn") String sn) {
        String url = baseUrl + "/contract/createbycategory";
        String[] documents = new String[1];
        documents[0] = documentId;
        List<Object> signatories = new ArrayList<>();
        String[] teantNameList = tenantNameForSign.split(",");
        String[] contactList = contact.split(",");
        for (int i = 0; i < teantNameList.length; i++) {
            Map<String, Object> signatory = new HashMap<>();
            signatory.put("tenantType", "PERSONAL");
            signatory.put("tenantName", teantNameList[i]);
            signatory.put("contact", contactList[i]);
            signatory.put("serialNo", 1);
            List<Object> actionList = new ArrayList<>();
            Map<String, Object> action = new HashMap<>();
            action.put("type", "PERSONAL");
            action.put("name", "个人签字");
            action.put("serialNo", 1);
            actionList.add(action);
            signatory.put("actions", actionList);
            signatories.add(signatory);
        }

        Map<String, Object> formData = new HashMap<>();
        formData.put("subject", subject);
        formData.put("documents", documents);
        formData.put("tenantName", tenantName);
        formData.put("createName", createName);
        formData.put("creatorContact", creatorContact);
        formData.put("categoryId", categoryId);
        formData.put("send", true);
        formData.put("signatories", signatories);
        formData.put("sn", sn);
        formData.put("businessData", getCurrDs());
        JSONObject json = new JSONObject(formData);
        return ADOConnection.runTask(getCurrDs(), electronicSignatureService, "createByCategory", Response.class, url, json, headerParams, workTicketId, documentId);
    }

    @PostMapping(value = "/callback")
    @ApiOperation(value = "单次签发回调函数")
    public Response callback(HttpServletRequest request) throws IOException {
        String body = request.getReader().lines().collect(Collectors.joining(System.lineSeparator()));
        log.info("电子签章回调:{}", body);
        String[] variables = body.split("&");
        String contractId = "";
        String tenantName = "";
        String contact = "";
        String status = "";
        String sn = "";
        String type = "";
        for (String variable : variables) {
            String[] pair = variable.split("=");
            if (pair[0].contains("contractId")) {
                contractId = pair[1];
            } else if (pair[0].contains("tenantName")) {
                tenantName = pair[1];
            } else if (pair[0].contains("status")) {
                status = pair[1];
            } else if (pair[0].contains("sn")) {
                sn = pair[1];
            } else if (pair[0].contains("contact")) {
                contact = pair[1];
            } else if ("type".equals(pair[0])) {
                type = pair[1];
            }
        }
        String decode = URLDecoder.decode(tenantName, "UTF-8");

        if (sn.equals("workTicket")) {
            return ADOConnection.runTask(getCurrDs(), electronicSignatureService, "callback", Response.class, contractId, decode, status);
        } else if (sn.equals("experiment")) {
            return ADOConnection.runTask(getCurrDs(), electronicSignatureService, "callbackExperiment", Response.class, contractId, decode, contact, type, status);
        } else {
            return Response.fail("没有对应的业务模块");
        }
    }

    @GetMapping("/downloadDocument")
    @ApiOperation("根据文档id下载文档")
    @ApiImplicitParam(name = "documentId", value = "文档id", required = true, dataType = "String")
    public void downloadDocument(@RequestParam("documentId") String documentId, HttpServletResponse response) {
        String url = baseUrl + "/document/download?documentId=" + documentId;
        CloseableHttpClient httpClient = HttpClients.createDefault();
        try {
            // 1. 请求链接
            HttpGet httpGet = new HttpGet(url);
            // 2. 设置请求头
            if (headerParams != null && headerParams.size() > 0) {
                for (Map.Entry<String, String> pair : headerParams.entrySet()) {
                    String value = pair.getValue();
                    String key = pair.getKey();
                    if (StringUtils.isNotEmpty(value)) {
                        httpGet.setHeader(key, value);
                    }
                }
            }
            // 3. 获取返回的流数据
            HttpResponse httpResponse = httpClient.execute(httpGet);// 执行提交
            HttpEntity entity = httpResponse.getEntity();
            InputStream in = entity.getContent();
            // 4. 设置返回的请求头
            response.setContentType("application/pdf");
            response.setHeader("Content-Disposition", "attachment");
            // 5. 将input流写入output流;下面注释中的写法不行，不知道为什么，猜测跟文件大小有关（未验证）
//                        if (in.read() != -1) {
//                                response.getOutputStream().write(in.read());
//                        }
            IOUtils.copy(in, response.getOutputStream());
        } catch (ClientProtocolException e) {
            log.error(e.getMessage(), e);
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        }

    }

    @GetMapping("/updateAttachMent")
    @ApiOperation("根据文档id下载文档,然后更新到附件")
    @ApiImplicitParam(name = "documentId", value = "文档id", required = true, dataType = "String")
    public Response<String> updateAttachMent(@RequestParam String documentId) {

        Assert.notNull(documentId, "文档id不能为空");
        File file = null;
        FileOutputStream fileOutputStream = null;

        String url = baseUrl + "/document/download?documentId=" + documentId;
        CloseableHttpClient httpClient = HttpClients.createDefault();
        InputStream byteArrayInputStream = null;
        try (ByteArrayOutputStream output = new ByteArrayOutputStream(4096);) {
            // 1. 请求链接
            HttpGet httpGet = new HttpGet(url);
            // 2. 设置请求头
            if (headerParams != null && headerParams.size() > 0) {
                for (Map.Entry<String, String> pair : headerParams.entrySet()) {
                    String value = pair.getValue();
                    String key = pair.getKey();
                    if (StringUtils.isNotEmpty(value)) {
                        httpGet.setHeader(key, value);
                    }
                }
            }
            // 3. 获取返回的流数据
            HttpResponse httpResponse = httpClient.execute(httpGet);// 执行提交
            HttpEntity entity = httpResponse.getEntity();
            InputStream in = entity.getContent();

            IOUtils.copyLarge(in, output);
            byte[] bytes = output.toByteArray();
            byteArrayInputStream = new ByteArrayInputStream(bytes);
            String fileUrl = null;
            long fileSize = bytes.length;
            fileUrl = fdfsCient.uploadFile(byteArrayInputStream, fileSize, "pdf");

            ElectronicSignatureQuery electronicSignatureQuery = new ElectronicSignatureQuery();
            electronicSignatureQuery.setDocumentId(documentId);
            ElectronicSignature electronicSignature = ADOConnection.runTask(getCurrDs(), electronicSignatureService, "getSingle", ElectronicSignature.class, electronicSignatureQuery);

            String workTicketId = electronicSignature.getWorkTicketId();

            Attachment attachment = new Attachment();
            attachment.setType(workTicketId);
            attachment.setPath(fileUrl);
            attachment.setSize(Double.parseDouble(fileSize + ""));
            attachment.setExtension("pdf");

            int i = attachmentService.updateAttachment(attachment);

            return Response.ok(fileUrl);
        } catch (ClientProtocolException e) {
            log.error(e.getMessage(), e);
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        } finally {
            if (byteArrayInputStream != null) {
                try {
                    byteArrayInputStream.close();
                } catch (IOException e) {
                    log.error(e.getMessage(), e);
                }
            }
        }
        return null;
    }

}
